/**
 * @file ControlCollege.hpp
 * @brief 集中管理所有设备接口
 */

#ifndef CONTROL_COLLEGE_H
#define CONTROL_COLLEGE_H

#include "ControlObj.hpp"
#include <map>
#include <functional>
#include "CameraDriver/Base/Driver.hpp"
#include "FileForamtBuilder.hpp"
#include <list>

/**
 * @class ControlCollege
 * @brief 设备控制接口管理器
 */
class ControlCollege
{
    friend class ControlObj;
    /**
     * @brief 设备控制对象列表
     */
    std::map<std::string,ControlObj*> conlist;
    /**
     * @brief 驱动列表
     */
    std::list<BaseDriver*> driverList;
    /**
     * @brief 文件格式列表
     */
    std::deque<BaseFileFormatBuilder*> formatList;
    /**
     * @brief 提交一个设备的下线
     *
     * @param uuid 设备UUID
     */
    void HandleOffline(std::string uuid);
    /**
     * @brief 快速从列表中获取设备
     * @return conlist的指针
     * @exception std::runtime_error 找不到该UUID
     *
     * @param uuid 设备UUID
     */
    decltype(conlist)::iterator SearchListItem(const std::string& uuid);
    /**
     * @brief 下线设备回收线程
     */
    std::jthread GCThread;
    /**
     * @brief 下线设备回收队列
     */
    SafeQueue<std::string> GCqueue;
  public:
    /**
     * @brief 构造函数
     */
    ControlCollege();
    virtual ~ControlCollege();
    /**
     * @brief 启动程序
     * @warning 要求在调用该函数前完成以下操作
     * 1. 设置`funcMsg`
     * 2. 设置`funcCameraOffline`
     * 3. 通过`AppendFileFormat`添加可用的文件格式
     * 4. 通过`operator<<`添加可用的相机驱动程序
     */
    void Boot();
    /**
     * @brief 添加相机驱动程序
     *
     * @param driver 继承于`BaseCamera`的相机驱动
     * @return 该对象的引用
     */
    ControlCollege& operator<<(BaseDriver* driver);
    /**
     * @brief 获取所有设备
     * @return 所有设备UUID列表
     */
    std::vector<std::string> GetAllDevice();
    /**
     * @brief 开始拍摄
     *
     * @param uuid 设备UUID
     */
    void StartShot(std::string uuid);
    /**
     * @brief 停止拍摄
     *
     * @param uuid 设备UUID
     */
    void StopShot(std::string uuid);
    /**
     * @brief 拍摄状态
     *
     * @param uuid 设备UUID
     * @return `true`正在拍摄,`false`没有拍摄
     */
    bool ShotStatus(std::string uuid);
    /**
     * @brief 开始录制
     *
     * @param uuid 设备UUID
     * @param path 文件存储录制
     * @param format 文件格式索引
     * 索引编号为`GetAllFormat()`返回的列表中位置
     */
    void StartRecord(std::string uuid,std::string path,int format);
    /**
     * @brief 停止录制
     *
     * @param uuid 设备UUID
     */
    void StopRecord(std::string uuid);
    /**
     * @brief 录制状态
     *
     * @param uuid 设备UUID
     * @return `true`正在录制，`false`没有录制
     */
    bool RecordStatus(std::string uuid);
    /**
     * @brief 获取实时帧率
     * @note 有些设备的帧率可能不是整数（设备时钟等原因），该函数返回值设计为浮点
     *
     * @param uuid 设备UUID
     * @return 帧率
     */
    float GetFPS(std::string uuid);
    /**
     * @brief 获取所有格式
     * @return 文件格式列表
     */
    std::vector<std::string> GetAllFormat();
    /**
     * @brief 获取共享内存信息
     * @return JSON字符串
     * **示例**
     * ```json
     * {
     *   "MemName" : "TEST_MEM_NAME",
     *   "SemName" : "TEST_SEM_NAME",
     *   "Size" : 1024
     * }
     * ```
     * **结构说明**
     * 名称 | 数据类型 | 描述
     * ---- | -------- | ----
     * MemName | String | 共享内存名称
     * SemName | String | 信号量名称
     * Size | long | 共享内存大小
     *
     * @param uuid 设备UUID
     */
    std::string/*json*/ GetShareMemInfo(std::string uuid);
    /**
     * @brief 获取参数列表
     * @return JSON字符串
     * @note 具体格式参见`ControlObj::GetSettingList`
     *
     * @param uuid 设备UUID
     */
    std::string/*json*/ GetSettingList(std::string uuid);
    /**
     * @brief 获取设备参数
     * @return JSON字符串
     * @note 具体格式参见`ControlObj::GetSettingValue`
     *
     * @param uuid 设备UUID
     * @param setid 设置ID
     */
    std::string/*json*/ GetSettingValue(std::string uuid,long setid);
    /**
     * @brief 设置设备参数
     * @return `true`执行成功,`false`执行失败
     * @note 具体格式参见`ControlObj::SetSettingValue`
     *
     * @param uuid 设备UUID
     * @param value JSON格式设置值
     */
    bool SetSettingValue(std::string uuid,std::string value/*json*/);
    /**
     * @brief 相机下线
     *
     * @param uuid 设备UUID
     */
    void Offline(std::string uuid);
    /**
     * @brief 获取预览信息
     * @note 要求在设备任何状态下都能正常调用函数
     *
     * @param uuid 设备UUID
     * @return json字符串
     * **示例**
     * ```json
     * {
     *   "Height": 1920,
     *   "Width": 1080,
     *   "Format": 0
     * }
     * ```
     * **结构说明**
     * 名称 | 数据类型 | 描述
     * ---- | -------- | ----
     * Height | int | 图片高度
     * Width | int | 图片宽度
     * Format | int(enum) | 图片格式
     *      
     * 其中图片格式定义于`Client.thrift`中`ImageFormat`枚举
     */
    std::string GetPreviewImgInfo(std::string uuid);
    /**
     * @brief 发送消息
     * @note
     * 回调函数   
     * `void Msg (std::string msg)`   
     * **参数**    
     * 1. 消息内容
     */
    std::function<void(std::string/*msg*/)> funcMsg;
    /**
     * @brief 相机掉线回掉函数
     * @note
     * 回调函数   
     * `void CameraOffline(std::string uuid)`   
     * **参数**   
     * 1. 设备UUID
     */
    std::function<void(std::string/*uuid*/)> funcCameraOffline;
    /**
     * @brief 添加文件格式
     *
     * @tparam T 继承于'BaseFormat'的类
     * @param formatname 格式名称
     */
    template<class T>
    void AppendFileFormat(const std::string& formatname)
    {
      formatList.push_back(dynamic_cast<BaseFileFormatBuilder*>(new FileFormatBuilder<T>(formatname)));
    }
};

#endif
